package com.jeasonzhao.report.tool;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.jeasonzhao.commons.basic.StringPair;
import com.jeasonzhao.commons.basic.StringPairCollection;
import com.jeasonzhao.commons.logger.MessageBasedLogListener;
import com.jeasonzhao.commons.parser.lex.JavaTokenizer;
import com.jeasonzhao.commons.parser.lex.LexException;
import com.jeasonzhao.commons.parser.lex.LexToken;
import com.jeasonzhao.commons.parser.lex.LexTokenCollection;
import com.jeasonzhao.commons.utils.Algorithms;
import com.jeasonzhao.commons.utils.ResourceHelper;

public class PortSourceCodeFromJava
{
    private String m_rootDirectory = null;
    private String m_rootJavaSourceCode = null;
    private String m_rootDotNetSourceCode = null;
    private String[] m_subFoldersForPort = new String[]
        {
        "Excel",
        null
    };
    public PortSourceCodeFromJava()
        throws Exception
    {
        m_rootDirectory = ResourceHelper.getClassLocationDirectory(PortSourceCodeFromJava.class);
        File f = new File(m_rootDirectory);
        m_rootDirectory = f.getParentFile().getAbsolutePath();
        m_rootJavaSourceCode = new File(m_rootDirectory + "/" + "SourceCode").getAbsolutePath();
        m_rootDotNetSourceCode = new File(m_rootDirectory + "/" + "DotNet2").getAbsolutePath();
        log("The root of source code folder is> " + m_rootDirectory);
        log("The Java source code folder is> " + m_rootJavaSourceCode);
        log("The DotNet source code folder is> " + m_rootDotNetSourceCode);
    }

    private void log(String str)
    {
        System.out.println(MessageBasedLogListener.formatMessage("Info",null,str,null));
    }

    private void log(Exception ex)
    {
        System.out.println(MessageBasedLogListener.formatMessage("Info",null,ex.getMessage(),ex));
    }

    private void port()
        throws Exception
    {
        for(String subFolder : m_subFoldersForPort)
        {
            if(Algorithms.isEmpty(subFolder))
            {
                continue;
            }
            File f = new File(m_rootJavaSourceCode,subFolder);
            if(f.exists() == false || f.isDirectory() == false)
            {
                log("Could not found the specified directory : " + f.getAbsolutePath());
            }
            processFolder(null,f.getAbsolutePath()); //Begin folder is empty
        }
    }

    private void copyfile(String srFile,String dtFile)
    {
        try
        {
            log("\t\tCopying file " + srFile + ">" + dtFile);
            File f1 = new File(srFile);
            File f2 = new File(dtFile);
            InputStream in = new FileInputStream(f1);
            OutputStream out = new FileOutputStream(f2);
            byte[] buf = new byte[1024];
            int len;
            while((len = in.read(buf)) > 0)
            {
                out.write(buf,0,len);
            }
            in.close();
            out.close();
        }
        catch(FileNotFoundException ex)
        {
            log(ex);
        }
        catch(IOException e)
        {
            log(e);
        }
    }

    private void processFolder(String strFolderShortDir,String strFolderName)
        throws FileNotFoundException,IOException,LexException
    {
        String strDestinationFolderName = Algorithms.isEmpty(strFolderShortDir)
            ? m_rootDotNetSourceCode : new File(this.m_rootDotNetSourceCode,strFolderShortDir).getAbsolutePath();
        log("Begin parse folder >" + strFolderName);
        log("                to >" + strDestinationFolderName);
        File newFolder = new File(strDestinationFolderName);
        if(newFolder.mkdirs() == false)
        {
            throw new IOException("Could not buld folder " + newFolder.getAbsolutePath());
        }
        File folder = new File(strFolderName);
        for(File f : folder.listFiles())
        {
            if(f.getName().equalsIgnoreCase(".svn"))
            {
                continue;
            }
            if(f.isDirectory())
            {
                if(f.getName().equals("db"))
                {
                    continue;
                }
                String strSubFolderShortDir = (Algorithms.isEmpty(strFolderShortDir) ? "" : strFolderShortDir + "/") + f.getName();
                processFolder(strSubFolderShortDir,f.getAbsolutePath());
            }
            else
            {
                String strExtends = f.getAbsolutePath();
                String strFileNameParts = f.getName();
                int n = strExtends.lastIndexOf(".");
                if(n > 0)
                {
                    strExtends = strExtends.substring(n + 1);
                    n = strFileNameParts.lastIndexOf(".");
                    strFileNameParts = strFileNameParts.substring(0,n);
                }
                else
                {
                    strExtends = null;
                }
                if(Algorithms.isEmpty(strExtends))
                {
                    continue; //Skip the files has no extension.
                }
                else if("java".equalsIgnoreCase(strExtends))
                {
                    processJavaFile(f.getAbsolutePath(),strDestinationFolderName + "/" + strFileNameParts + ".cs");
                }
                else
                {
                    copyfile(f.getAbsolutePath(),strDestinationFolderName + "/" + f.getName());
                }
            }
        }
    }

    private void processJavaFile(String strSourceFileName,String strDestinationFolderName)
        throws FileNotFoundException,IOException,LexException
    {
        log("\t\t" + strSourceFileName + ">" + strDestinationFolderName);
        JavaTokenizer sqltokenizer = new JavaTokenizer();
        sqltokenizer.loadFile(strSourceFileName);
        LexTokenCollection tks = sqltokenizer.getTokens(true,true);
        StringPairCollection NamePairs = StringPairCollection.from(
            "equals:Equals;super:base;params:parameters;instanceof:is;addElement:Add;"
            + "length:Length;size:Count;java.util.Vector:List;Vector:List;"
            + "equals:Equals;trim:Trim;toLowerCase:ToLower;startsWith:StartsWith;endsWith:EndsWith;"
            + "indexOf:IndexOf;lastIndexOf:LastIndexOf;toString:ToString;substring:Substring;"
            + "abs:Abs;synchronized:lock;toUpperCase:ToUpper;max:Max;min:Min;string:strValueParam;"
            + "Class:Type;java.util.Hashtable:Dictionary;StringBuffer:StringBuilder;append:Append;"
            + "boolean:bool;System.out.println:System.Console.WriteLine;"
            ,";",":");
        String strRet = "";
        for(int n = 0;n < tks.size();n++)
        {
            LexToken token = tks.get(n);
            LexToken tokenNext = n + 1 < tks.size() ? tks.get(n + 1) : null;
            LexToken tokenNext2 = n + 2 < tks.size() ? tks.get(n + 2) : null;
            LexToken tokenNext3 = n + 2 < tks.size() ? tks.get(n + 2) : null;
            if(token.isName())
            {
                if(token.getToken().equals("import"))
                {
                    token.setToken("using");
                    if(tokenNext.getToken().startsWith("java"))
                    {
                        n += 2;
                        token = null;
                    }
                    else
                    {
                        String strLast = tokenNext.getToken();
                        int nx = strLast.lastIndexOf(".");
                        if(nx > 0)
                        {
                            n++;
                            strLast = strLast.substring(0,nx);
                            token.setToken("using " + strLast);
                        }
                    }
                }
                else if(token.getToken().equals("package"))
                {
                    token.setToken("using System;using System.Collections.Generic;using System.Text;namespace");
                    strRet += (token.getInitString());
                    strRet += (tokenNext.getInitString());
                    strRet += ("{");
                    n += 2;
                    token = null;
                }
                else if(token.getToken().equals("extends"))
                {
                    token.setToken(":");
                }
                else if(token.getToken().equals("throws"))
                {
                    token = null;
                    int nx = n + 1;
                    for(;nx < tks.size();nx++)
                    {
                        if(tks.get(nx).isName() ||
                           tks.get(nx).getToken().equals(","))
                        {
                            n++;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                else if(token.getToken().equals("implements"))
                {
                    token.setToken(":");
                }
                else if(token.getToken().equals("final")
                        && null != tokenNext
                        && tokenNext.isName()
                        && tokenNext.getToken().equals("class"))
                {
                    token.setToken("");
                }
                else if(token.getToken().equals("final"))
                {
                    token = null;
                }
                else if(null != tokenNext3 && null != tokenNext && null != tokenNext2
                        && tokenNext3.isSpecial() && tokenNext3.equals(".")
                        && tokenNext.isSpecial() && tokenNext.equals(".")
                        && tokenNext2.isSpecial() && tokenNext2.equals("."))
                {
                    token.setToken("params " + token.getToken() + "[] ");
                    n += 3;
                }
                else if(token.getToken().charAt(0) == '$')
                {
                    token.setToken("__" + token.getToken().substring(1));
                }
                else if(token.getToken().endsWith(".class"))
                {
                    token.setToken("typeof(" + token.getToken().substring(0,token.getToken().length() - 6) + ")");
                }
                else if(null != token)
                {
                    for(StringPair p : NamePairs)
                    {
                        if(null != p && Algorithms.notEmpty(p.getFirst())
                           && Algorithms.notEmpty(p.getSecond()))
                        {
                            if(token.getToken().equals(p.getFirst()))
                            {
                                token.setToken(p.getSecond());
                            }
                            else if(token.getToken().endsWith("." + p.getFirst()))
                            {
                                token.setToken(token.getToken().substring(0,token.getToken().length() - p.getFirst().length()) +
                                               p.getSecond());
                            }

                        }
                    }
                }
            }
            if(null != token)
            {
                strRet += (token.getInitString());
            }
        }
        strRet += "}";
        strRet = strRet
            .replaceAll("\\.Count\\(\\)",".Count")
            .replaceAll("\\.Count\\(\\)",".Count")
            .replaceAll("this\\.get\\(n\\)","this[n]")
            .replaceAll("\\.Length\\(\\)",".Length")
            .replaceAll("base\\(\\);","")
            .replaceAll("\\.getMessage\\(\\)",".Message")
            .replaceAll("add\\(","Add(")
            .replaceAll("new java\\.util\\.Date\\(\\)","DateTime.Now")
            .replaceAll("new Date\\(\\)","DateTime.Now")
            .replaceAll("public bool Equals\\(","public override bool Equals(")
            ;
        FileWriter fw = new FileWriter(strDestinationFolderName,false);
        fw.write(strRet);
        fw.flush();
        fw.close();
    }

    public static void main(String[] argvs)
        throws Exception
    {
        PortSourceCodeFromJava a = new PortSourceCodeFromJava();
        a.port();
    }
}
